home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 February: Tool Chest / Dev.CD Feb 95 / Dev.CD Feb 95.toast / Sample Code / Sprocket / Lib / DialogUtils.cp < prev    next >
Encoding:
Text File  |  1994-11-23  |  10.4 KB  |  406 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DialogUtils.cp
  3.  
  4.     Contains:    Auto-sized error alert mechanism,
  5.                 ModalFilterProcs which correctly handle events,
  6.                 and Standard “Close Document” dialogs. 
  7.  
  8.     Written by: Dave Falkenburg
  9.  
  10.     Copyright:    © 1993-94 by Dave Falkenburg, all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.      
  14.          <6>    11/23/94    DRF        Add ToggleCheckBox, a nice little dialog item utility.
  15.          <5>    11/16/94    DRF        Added explicit #include <SegLoad.h> for latest universal
  16.                                     headers. Also added cast to keep MPW CFront happier.
  17.          <4>    11/16/94    DRF        Add StdFilterProc for THINK C.
  18.          <3>     9/27/94    DRF         AppLib.h is now Sprocket.h
  19.          <2>      9/9/94    DRF        Reordered headers and removed redundant #includes.
  20.  */
  21.  
  22. #include "Sprocket.h"
  23.  
  24. #include <Fonts.h>
  25. #include <Resources.h>
  26. #include <TextUtils.h>
  27. #include <Threads.h>        //    For YieldToAnyThread()
  28. #include <StandardFile.h>    //    For ModalFilterYDProcPtr
  29. #include <SegLoad.h>        //    For ExitToShell()
  30.  
  31. //    Some types which should probably be defined in <Dialogs.h>
  32. //    NOTE: These must be aligned on 2-byte boundaries
  33. #if defined(powerc) || defined (__powerc)
  34. #pragma options align=mac68k
  35. #endif
  36.  
  37. struct DialogItem
  38.     {
  39.     long    usedByDialogManager;
  40.     Rect    boundsRect;
  41.     char    type;
  42.     char    length;
  43.     };
  44.  
  45. struct DialogItemList            //    a.k.a. a 'DITL'
  46.     {
  47.     short        count;
  48.     DialogItem    firstItem[1];
  49.     };
  50.  
  51. //    Restore default alignment
  52. #if defined(powerc) || defined(__powerc)
  53. #pragma options align=reset
  54. #endif
  55.  
  56. typedef    DialogItem        *DialogItemPtr;
  57. typedef    DialogItemList    **DialogItemListHandle;
  58. typedef    DialogTemplate    **DialogTemplateHandle;
  59.  
  60. #ifndef    powerc
  61. #ifdef    __SC__
  62.  
  63. extern pascal OSErr GetStdFilterProc(ModalFilterUPP *theProc)
  64.  THREEWORDINLINE(0x303C, 0x0203, 0xAA68);
  65.  
  66. pascal Boolean
  67. StdFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  68.     {
  69.     ModalFilterUPP    filterUPP;
  70.  
  71.     //    Dialogs.h
  72.     
  73.     (void) GetStdFilterProc(&filterUPP);
  74.  
  75.     return    CallModalFilterProc(filterUPP,theDialog,anEvent,itemHit);
  76.     }
  77.  
  78. #endif
  79. #endif
  80.  
  81. //    private function Prototypes
  82.  
  83. static    pascal Boolean    StandardDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  84. static    pascal Boolean    StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit, void * yourData);
  85. static    pascal Boolean    StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  86. static    Boolean            FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  87.  
  88.  
  89.  
  90. ///////////////////////////////////////////////////////////
  91. //
  92. //    StandardAlert
  93. //
  94. //    An alternative to Alert() which uses the extended
  95. //    Dialog Manager capabilities.
  96. //
  97. //    I’m not sure we really need this call, but it seems
  98. //    to do the trick just fine.
  99.  
  100. short
  101. StandardAlert(    short dlogID,
  102.                 short defaultItem,                /* = ok */
  103.                 short cancelItem,                /* = 0 */
  104.                 ModalFilterUPP customFilterProc    /* = nil */)
  105.     {
  106.     DialogPtr        theDialog;
  107.     short            itemHit = 0;
  108.     ModalFilterUPP    filterToUse;
  109.     
  110.     HiliteWindowsForModalDialog(false);
  111.  
  112.     theDialog = GetNewDialog(dlogID,nil,(WindowPtr) -1);
  113.     if (defaultItem)
  114.         SetDialogDefaultItem(theDialog,defaultItem);
  115.     if (cancelItem)
  116.         SetDialogCancelItem(theDialog,cancelItem);
  117.  
  118.     if (customFilterProc)
  119.         filterToUse = customFilterProc;
  120.     else
  121.         filterToUse = StandardDialogFilter;
  122.  
  123.     do
  124.         ModalDialog(filterToUse,&itemHit);
  125.     while (itemHit == 0);
  126.     
  127.     DisposeDialog(theDialog);
  128.  
  129.     HiliteWindowsForModalDialog(true);
  130.  
  131.     return itemHit;
  132.     }
  133.  
  134.  
  135. ///////////////////////////////////////////////////////////
  136. //
  137. //    ErrorAlert
  138. //
  139. //    A nice error reporting routine which presents an
  140. //    auto-sized alert box containing the supplied text.
  141. //
  142. //    NOTE:    This routine ASSUMES the following 'DITL'
  143. //            structure:
  144. //
  145. //            item #1 : an “OK” button
  146. //            item #2 : a static text item, somewhere above #1
  147. //
  148. //    NOTE:    We probably need to worry more about low
  149. //            memory conditions-- this can probably
  150. //            be handled by a custom GrowZoneProc and
  151. //            reserve memory area large enough to hold
  152. //            all the space we’d need.
  153. //
  154.  
  155. void
  156. ErrorAlert(short stringList,short whichString)
  157.     {
  158.     Str255                    errorString;
  159.     GrafPtr                    oldPort,windowMgrPort;
  160.     short                    oldFont;
  161.     DialogTemplateHandle    errorDialogTemplate;
  162.     DialogItemListHandle    errorDialogItems;
  163.     TEHandle                aTEHandle;
  164.     Rect                    textRect;
  165.     short                    textHeight;
  166.     short                    additionalSpaceNeeded;
  167.     DialogItemPtr            okButtonItem,errorTextItem;
  168.     const StringPtr            nullStr = (StringPtr) "\p";
  169.  
  170.     GetIndString(errorString,stringList,whichString);
  171.     
  172.     errorDialogTemplate = (DialogTemplateHandle) Get1Resource('DLOG',kErrorAlertID);
  173.     HLock((Handle) errorDialogTemplate);
  174.     
  175.     errorDialogItems = (DialogItemListHandle) Get1Resource('DITL',(**errorDialogTemplate).itemsID);
  176.     HLock((Handle) errorDialogItems);
  177.     
  178.     //    Find the dialog items
  179.     
  180.     okButtonItem = (**errorDialogItems).firstItem;
  181.     errorTextItem = (DialogItemPtr) ((Ptr) okButtonItem + sizeof(DialogItem) + okButtonItem->length);
  182.     
  183.     GetPort(&oldPort);
  184.     GetWMgrPort(&windowMgrPort);
  185.     SetPort(windowMgrPort);
  186.     oldFont = qd.thePort->txFont;
  187.     TextFont(systemFont);
  188.  
  189.     aTEHandle = TENew(&textRect,&textRect);
  190.     TESetText(&errorString[1],errorString[0],aTEHandle);
  191.     textHeight = (*aTEHandle)->lineHeight * (*aTEHandle)->nLines;
  192.     TEDispose(aTEHandle);
  193.  
  194.     additionalSpaceNeeded = textHeight - (errorTextItem->boundsRect.bottom
  195.                             - errorTextItem->boundsRect.top);
  196.  
  197.     if (additionalSpaceNeeded > 0)
  198.         {
  199.         (**errorDialogTemplate).boundsRect.bottom += additionalSpaceNeeded;
  200.         errorTextItem->boundsRect.bottom += additionalSpaceNeeded;
  201.         OffsetRect(&okButtonItem->boundsRect,0,additionalSpaceNeeded);
  202.         }
  203.         
  204.     TextFont(oldFont);
  205.     SetPort(oldPort);
  206.     
  207.     InitCursor();
  208.     ParamText(errorString,nullStr,nullStr,nullStr);
  209.  
  210.     (void) StandardAlert(kErrorAlertID);
  211.  
  212.     ReleaseResource((Handle) errorDialogTemplate);
  213.     ReleaseResource((Handle) errorDialogItems);
  214.     }
  215.  
  216.  
  217. ///////////////////////////////////////////////////////////
  218. //
  219. //    FatalErrorAlert
  220. //
  221. //    A companion to ErrorAlert which also kills the process.
  222. //
  223.  
  224. void
  225. FatalErrorAlert(short stringList,short whichString)
  226.     {
  227.     ErrorAlert(stringList,whichString);
  228.     ExitToShell();
  229.     }
  230.  
  231.  
  232. ///////////////////////////////////////////////////////////
  233. //
  234. //    StandardDialogFilter and StandardDialogFilterYD
  235. //
  236. //    These function takes care of routing events not meant
  237. //    for the dialog window to other parts of the application.
  238. //
  239. //    Use them as an alternative to passing a NIL ModalFilterProc
  240. //    to ModalDialog() and CustomGet(Put)File. Unlike the default
  241. //    filter, these routines properly processes update events
  242. //    to keep background processes running.
  243. //
  244. //    The Thread Manager, if present, is also called to yield
  245. //    control to other cooperative threads within the process.
  246. //
  247. //    Because of pascal calling conventions we need two separate
  248. //    routines, but this is minimized by sharing implementation
  249. //    in FilterProcCommon.
  250. //
  251.  
  252. ModalFilterUPP    StandardDialogFilter
  253. = NewModalFilterProc(StandardDialogFilterProc);
  254.  
  255. ModalFilterYDUPP    StandardDialogFilterYD
  256. = NewModalFilterYDProc(StandardDialogFilterYDProc);
  257.  
  258. ModalFilterUPP    StandardCloseDialogFilter
  259. = NewModalFilterProc(StandardCloseDialogFilterProc);
  260.  
  261.  
  262. pascal Boolean
  263. StandardDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  264.     {
  265.     //    Call through common code to check for events we’d like to handle.
  266.     //    If that is unsuccessful, call through the System 7 StdFilterProc
  267.     //    to handle CR, “CMD-.” & ESC in an international-friendly manner.
  268.  
  269.     if (FilterProcCommon(theDialog, anEvent, itemHit))
  270.         return true;
  271.     else
  272.         return (StdFilterProc(theDialog, anEvent, itemHit));
  273.     }
  274.  
  275.  
  276. pascal Boolean
  277. StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit, void * /*unusedData*/)
  278.     {
  279.     //    We don’t call through to StdFilterProc since the
  280.     //    Standard File Package already does everything we need.
  281.  
  282.     return FilterProcCommon(theDialog, anEvent, itemHit);
  283.     }
  284.  
  285. void
  286. PseudoClickInDialogItem(DialogPtr theDialog, short itemToClick)
  287.     {
  288.     Handle    itemHandle;
  289.     Rect    itemBox;
  290.     long    finalTicks;
  291.     short    itemType;
  292.     
  293.     GetDialogItem(theDialog,itemToClick,&itemType,&itemHandle,&itemBox);
  294.  
  295.     HiliteControl((ControlHandle) itemHandle,inButton);
  296.     Delay(8,&finalTicks);
  297.     HiliteControl((ControlHandle) itemHandle,0);
  298.     }
  299.  
  300.  
  301. Boolean
  302. ToggleCheckBox(DialogPtr theDialog, short theCheckBox)
  303.     {
  304.     ControlHandle    itemHandle;
  305.     Rect            itemBox;
  306.     short            itemType;
  307.     
  308.     GetDialogItem(theDialog,theCheckBox,&itemType,(Handle *) &itemHandle,&itemBox);
  309.  
  310.     if (GetControlValue(itemHandle) == 1)
  311.         {
  312.         SetControlValue(itemHandle,0);
  313.         return false;
  314.         }
  315.     else
  316.         {
  317.         SetControlValue(itemHandle,1);
  318.         return true;
  319.         }
  320.     }
  321.  
  322.  
  323. pascal Boolean
  324. StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  325.     {
  326.     if ((anEvent->what == keyDown))
  327.         {
  328.         char    c = (char) anEvent->message & charCodeMask;
  329.         
  330.         if ((c == 'd') || (c == 'D'))                //    NOT INTERNATIONAL FRIENDLY!!!
  331.             {
  332.             *itemHit = kDontSaveDocument;
  333.             PseudoClickInDialogItem(theDialog,kDontSaveDocument);
  334.             return true;
  335.             }
  336.         }
  337.  
  338.     //    Return through the common code above so that default item processing can happen
  339.     return StandardDialogFilterProc(theDialog, anEvent, itemHit);
  340.     }
  341.  
  342.  
  343. Boolean
  344. FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * /* itemHit */)
  345.     {
  346.     switch (anEvent->what)
  347.         {
  348.         case updateEvt:
  349.         case activateEvt:
  350.             //     Update or activate for the dialog window?
  351.             if (theDialog == (DialogPtr) anEvent->message)
  352.                 break;
  353.  
  354.             //    no, fall through to HandleEvent            
  355.             
  356.         case diskEvt:
  357.             HandleEvent(anEvent);
  358.             return(false);
  359.  
  360.         default:
  361.             break;        
  362.         }
  363.  
  364.     if (gHasThreadManager)        //    If we have threads, let them run!
  365.         YieldToAnyThread();
  366.  
  367.     return false;                //    We didn’t handle the event
  368.     }
  369.  
  370.  
  371. //////////////////////////////////////////////////////////////////
  372. //
  373. //    StandardCloseDocument
  374. //
  375. //    Provides the standard human interface for closing a document
  376. //
  377. //    NOTE: When we make TDocument class, this will become a method
  378. //          and probably won’t need any parameters.
  379. //
  380. //    NOTE:    StandardCloseResult matches the dialog items for 
  381.  
  382. StandardCloseResult
  383. StandardCloseDocument(const StringPtr documentType, StringPtr documentName,
  384.                       Boolean hasNewEditions, Boolean quitting)
  385.     {
  386.     short        whichAlert;
  387.     short        whichString;
  388.     StringPtr    nullStr = (StringPtr) "\p";
  389.     Str255        reasonForClosingStr;
  390.  
  391.     if (hasNewEditions)
  392.         whichAlert = kStandardCloseWithNewPubsAlertID;
  393.     else
  394.         whichAlert = kStandardCloseAlertID;
  395.     
  396.     if (quitting)
  397.         whichString = kQuittingStr;
  398.     else
  399.         whichString = kClosingStr;
  400.  
  401.     GetIndString(reasonForClosingStr,kStandardCloseStrings,whichString);
  402.     ParamText(documentType,documentName,reasonForClosingStr,nullStr);
  403.     
  404.     return ((StandardCloseResult) StandardAlert(whichAlert,kSaveDocument,kCancelSaveDocument,StandardCloseDialogFilter));
  405.     }
  406.